package cn.iocoder.yudao.module.def.utils;

public class CoordinateTransformUtil {

    // 定义常量
    private static final double PI = Math.PI;
    private static final double A = 6378245.0; // 长半轴
    private static final double EE = 0.00669342162296594323; // 扁率

    /**
     * WGS84 转 GCJ02
     *
     * @param wgLat 纬度
     * @param wgLon 经度
     * @return 转换后的 GCJ02 坐标 [纬度, 经度]
     */
    public static double[] wgs84ToGcj02(double wgLat, double wgLon) {
        if (outOfChina(wgLat, wgLon)) {
            return new double[]{wgLat, wgLon};
        }

        double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
        double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
        double radLat = wgLat / 180.0 * PI;
        double magic = Math.sin(radLat);
        magic = 1 - EE * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((A * (1 - EE)) / (magic * sqrtMagic) * PI);
        dLon = (dLon * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI);
        double mgLat = wgLat + dLat;
        double mgLon = wgLon + dLon;

        return new double[]{mgLat, mgLon};
    }

    /**
     * GCJ02 转 BD09
     *
     * @param gcjLat 纬度
     * @param gcjLon 经度
     * @return 转换后的 BD09 坐标 [纬度, 经度]
     */
    public static double[] gcj02ToBd09(double gcjLat, double gcjLon) {
        double x = gcjLon, y = gcjLat;
        double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * PI);
        double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * PI);
        double bdLon = z * Math.cos(theta) + 0.0065;
        double bdLat = z * Math.sin(theta) + 0.006;

        return new double[]{bdLat, bdLon};
    }

    /**
     * WGS84 转 BD09
     *
     * @param wgLat 纬度
     * @param wgLon 经度
     * @return 转换后的 BD09 坐标 [纬度, 经度]
     */
    public static double[] wgs84ToBd09(double wgLat, double wgLon) {
        double[] gcj02 = wgs84ToGcj02(wgLat, wgLon);
        return gcj02ToBd09(gcj02[0], gcj02[1]);
    }

    /**
     * 判断是否在中国范围外
     *
     * @param lat 纬度
     * @param lon 经度
     * @return 是否在范围外
     */
    private static boolean outOfChina(double lat, double lon) {
        return !(lon > 73.66 && lon < 135.05 && lat > 3.86 && lat < 53.55);
    }

    /**
     * 计算纬度偏移
     */
    private static double transformLat(double x, double y) {
        double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
        return ret;
    }

    /**
     * 计算经度偏移
     */
    private static double transformLon(double x, double y) {
        double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0;
        return ret;
    }

    /**
     * 解析 WGS84 坐标字符串并转换为百度坐标字符串
     *
     * @param wgs84Coords WGS84 坐标字符串，格式为 "经度,纬度;经度,纬度;..."
     * @return 百度坐标字符串，格式为 "经度,纬度;经度,纬度;..."
     */
    public static String parseAndConvertToBd09(String wgs84Coords) {
        if (wgs84Coords == null || wgs84Coords.isEmpty()) {
            return "";
        }

        // 按分号分割每组坐标
        String[] coordPairs = wgs84Coords.split(";");
        StringBuilder bd09Result = new StringBuilder();

        for (String coordPair : coordPairs) {
            // 按逗号分割经纬度
            String[] latLon = coordPair.split(",");
            if (latLon.length != 2) {
                continue; // 忽略格式不正确的坐标对
            }

            try {
                double wgLat = Double.parseDouble(latLon[1].trim()); // 纬度
                double wgLon = Double.parseDouble(latLon[0].trim()); // 经度

                // 转换为百度坐标
                double[] bd09 = wgs84ToBd09(wgLat, wgLon);

                // 拼接结果
                if (bd09Result.length() > 0) {
                    bd09Result.append(";");
                }
                bd09Result.append(bd09[1]).append(",").append(bd09[0]); // 格式为 "经度,纬度"
            } catch (NumberFormatException e) {
                // 忽略无法解析的坐标对
                continue;
            }
        }

        return bd09Result.toString();
    }

    public static void main(String[] args) {
        String str="120.14080884,30.27423441;120.13675879,30.27388734;120.13237450,30.27352506;120.12973349,30.27365258;120.12612889,30.27392194;120.12055296,30.27434540;120.11993747,30.27437480;120.11574938,30.27449944;120.10925027,30.27364289;120.10801587,30.27308802;120.10790353,30.27306749;120.10731287,30.27486964;120.10674433,30.27671366;120.10628371,30.27819846;120.10611845,30.27885859;120.10538278,30.28105017;120.10466878,30.28353431;120.10440732,30.28436122;120.10380790,30.28639491;120.10318299,30.28863718;120.10627155,30.29089494;120.10239018,30.29201226;120.10206577,30.29522852;120.10228916,30.29570623;120.10323548,30.29570403;";
        System.out.println(parseAndConvertToBd09(str));
    }
}